#pragma once

#include <vex/policy/bool_convertible.h>
#include <vex/policy/hashable.h>
#include <vex/policy/totally_ordered.h>
#include <vex/policy/arrow_reachable.h>
#include <vex/policy/merge_policies.h>
#include <vex/core/as_any.h>
#include <boost/utility/identity_type.hpp>

namespace vex { namespace core {

    /// <summary>
    /// Policies common to all handles and associated utilities.
    /// </summary>
    /// Any handle value type derives from this class.
    template< class TClass, class TClassTraits, class TBase = policy::empty_base >
    struct handle_policy : public policy::merge_policies<
        TClass, TClassTraits, TBase,
        policy::bool_convertible,
        policy::hashable,
        policy::totally_ordered,
        policy::arrow_reachable
    >::type 
    {
        typedef TClassTraits traits;
        typedef typename traits::item_type item_type;
        typedef typename traits::contract_type contract_type;
        typedef typename traits::holder_type holder_type;
        typedef typename holder_type::element_type element_type;
        VEX_PROTECT_POLICY(handle_policy);
    };

    /// <summary>
    /// Support for getting the raw pointer out of the handle instance
    /// </summary>
    template< class TClass, class TClassTraits, class TBase> 
    auto get_pointer(handle_policy<TClass, TClassTraits, TBase> const & p_handle)
        -> decltype(p_handle.get())
    {
        return p_handle.get();
    }
}}

#define VEX_TRAITS_IS_DEPENDENT_NAME typename

#define VEX_TRAITS_IS_NOT_DEPENDENT_NAME

#define VEX_INTERNAL_ANY_HANDLE_DEFAULT_BODY_IMPL_TRAITS(VexAnyHandleTraitsName, VexDependentName) \
    typedef VexAnyHandleTraitsName traits; \
    typedef VexDependentName traits::item_type item_type; \
    typedef VexDependentName traits::holder_type holder_type; \
    typedef VexDependentName traits::contract_type contract_type;

#define VEX_INTERNAL_ANY_HANDLE_DEFAULT_BODY_IMPL(VexAnyHandleName) \
    VexAnyHandleName() : m_holder() {} \
    \
    explicit VexAnyHandleName(contract_type* p_contract, bool p_add_ref) \
        : m_holder(p_contract, p_add_ref) {} \
    \
    explicit VexAnyHandleName(holder_type const & p_holder) : m_holder(p_holder) {} \
    \
    explicit VexAnyHandleName(holder_type&& p_holder) : m_holder(std::move(p_holder)) {} \
    \
    VexAnyHandleName(VexAnyHandleName&& p_other) : m_holder(std::move(p_other.m_holder)) {} \
    \
    VexAnyHandleName& operator = (VexAnyHandleName&& p_other) \
    { \
        VexAnyHandleName(std::move(p_other)).swap(*this); \
        return *this; \
    } \
    \
    void swap(VexAnyHandleName& p_other) \
    { \
        m_holder.swap(p_other.m_holder); \
    } \
    \
    item_type get() const \
    { \
       return m_holder.get(); \
    }

#define VEX_ANY_HANDLE_DEFAULT_BODY_IMPL(VexAnyHandleName, VexAnyHandleTraitsName, VexTraitsIsDependentName) \
    VEX_INTERNAL_ANY_HANDLE_DEFAULT_BODY_IMPL_TRAITS(VexAnyHandleTraitsName, VexTraitsIsDependentName) \
    VEX_INTERNAL_ANY_HANDLE_DEFAULT_BODY_IMPL(VexAnyHandleName)